package com.lemurian.bankdata.action.base;

import java.util.ArrayList;
import java.util.List;

import javax.servlet.http.HttpServletRequest;

import org.apache.struts2.ServletActionContext;
import org.apache.struts2.dispatcher.SessionMap;
import org.apache.struts2.interceptor.validation.SkipValidation;
import org.owasp.esapi.ESAPI;
import org.springframework.beans.factory.annotation.Autowired;

import com.google.code.kaptcha.Constants;
import com.lemurian.bankdata.lite.authentication.BankDataPrincipal;
import com.lemurian.bankdata.lite.enums.UserStatus;
import com.lemurian.bankdata.lite.logger.BankDataLogger;
import com.lemurian.bankdata.lite.utils.GeneralConstant;
import com.lemurian.bankdata.services.UserService;
import com.lemurian.bankdata.utils.BaseAction;
import com.lemurian.entity.Menu;
import com.lemurian.entity.User;
import com.opensymphony.xwork2.ActionContext;
import com.opensymphony.xwork2.Preparable;
import com.opensymphony.xwork2.ValidationAware;

public class LoginAction extends BaseAction implements Preparable, ValidationAware{
	
	private static final long serialVersionUID = 1L;

	private BankDataLogger log = BankDataLogger.getLogger(LoginAction.class.getSimpleName());
	
    private String mappedRequest = "";
    private String previousPage = "", subaction = "";

    private String loginId = "", password = "", captchaInput = "";
    private String jsonMessage = "";
    
    private User user;
    
    @Autowired
    private UserService userService;
    
    public void prepare() throws Exception {
        setOnHome(true);
        try {
            /*if (ESAPI.securityConfiguration().getResourceDirectory() == null) {
                log.sInfo(": : : : : ESAPI.properties ready to define : : : : : ");
                ESAPI.securityConfiguration().setResourceDirectory("X:/Zona IT/Notaris Project/apps/ESAPI/resources/");
            } else if (!ESAPI.securityConfiguration().getResourceDirectory().equals("X:/Zona IT/Notaris Project/apps/ESAPI/resources/")) {
                log.sInfo(": : : : : ESAPI.properties already define but different path : : : : : ");
                ESAPI.securityConfiguration().setResourceDirectory("X:/Zona IT/Notaris Project/apps/ESAPI/resources/");
            } else {
                log.sInfo(": : : : : ESAPI.properties already define : : : : : ");
            }*/

            ESAPI.httpUtilities().setCurrentHTTP(getRequest(), getResponse());
            setRequest(getRequest());
            setActionPrefix("login");
        } catch (Exception ex) {
//            ex.printStackTrace();
            log.sInfo(":: ERROR : %s", ex.getMessage());
        }
    }
	
	@SkipValidation
	public String index() {
		
		if(getSession().get(GeneralConstant.USER_PRINCIPAL) != null ){
			return "index";
		}
		
		((SessionMap) ActionContext.getContext().getSession()).invalidate();

        setPreviousPage("index");
        setMappedRequest("login");
		
		return SUCCESS;
	}
	
	public String login() {
		
		if (getSession().get(GeneralConstant.USER_PRINCIPAL) != null) {
            return "index";
        }
		
		try {
			
			setPreviousPage("index");
            setMappedRequest("login");
            
            boolean validate = false;
            
            if(loginId != null && loginId.length() > 0 && password != null && password.length() > 0 ) {
            	
            	String captchaExpected = (String) ServletActionContext.getRequest().getSession().getAttribute(Constants.KAPTCHA_SESSION_KEY);
                log.sInfo("Check for captcha. input [%s] with expected [%s]", captchaInput, captchaExpected);
            	
                captchaInput = "11111";
                captchaExpected = "11111";
                if(captchaInput.equalsIgnoreCase(captchaExpected)) {
                	log.info("Captcha validation is true");
                	
                	user = userService.authenticate(loginId, password);
                	
                	if(user != null) {
                		BankDataPrincipal principal = iniciatePrincipal(user, ServletActionContext.getRequest());
                		getSession().put(GeneralConstant.USER_PRINCIPAL, principal);
                		
                		userService.saveSessionId(user, getRequest().getSession().getId());
                		
                		if (user.getStatus() != UserStatus.ACTIVE.code()) {

                            if (user.getStatus() == UserStatus.INACTIVE.code()) {

                                validate = true;
                                jsonMessage = "User is Not Active";

                            } else if (user.getStatus() == UserStatus.LOCKED.code()) {

                                validate = true;
                                jsonMessage = "User is Locked";
                            }

                        }
                		
                	} else {
                        validate = true;
                        jsonMessage = "Invalid Login Id and Password";
                    }

                } else {
                    validate = true;
                    jsonMessage = "Invalid Security Code";
                }

            } else {
                validate = true;
                jsonMessage = "Login Id and Password is Required";
            }
            
            if(validate) {
                
                userService.failCount(loginId);

                log.info(jsonMessage);
                
                System.out.println(": : : : : VALIDASI ["+jsonMessage+"]");
                
                ((SessionMap) ActionContext.getContext().getSession()).invalidate();
                
                return GeneralConstant.JSON;
            } else {
            	log.info("Login Success Reset User Status & Fail Count");
            	
            	user = userService.resetFailCount(user);
            }
            
		} catch (Throwable t) {
            t.printStackTrace();
            addActionError("Some error occured. Please try to login again");
        }
		
		jsonMessage = "Success";
		return GeneralConstant.JSON;
		//return "index";
	}
	
	@SkipValidation
    public String logout() {
        log.sInfo(":: LOGGING OUT");
        
        try {

        } catch (Exception ex) {
            log.sInfo(":: ERROR LOGGING OUT : %s", ex.getMessage());
        }
        
        getSession().clear();
        if (getSession() instanceof SessionMap) {
            try {
                ((SessionMap) getSession()).invalidate();
            } catch (IllegalStateException ise) {
                String msg = "'LoginAction.logout' caught an " + "IllegalStateException, possibly because the session " + "has already been invalidated or timed out.";
                log.info(msg);
            }
        }
        
        setMappedRequestFullPath("/index.html");
        return "index";
    }
	
	public BankDataPrincipal iniciatePrincipal(User user, HttpServletRequest request) {
		BankDataPrincipal principal = new BankDataPrincipal();

        try {

            principal.setUser(user);
            principal.setRemoteAddress(request.getRemoteAddr());
            principal.setSessionId(request.getSession().getId());
            principal.setBrowser(SUCCESS);

            List<Menu> userMenus = userService.getListMenu(user); 
            List<Menu> distinctUserMenus = new ArrayList<Menu>();
            List<String> userMenuNames = new ArrayList<String>();
            
            log.sInfo("got total all granted menu : %s", userMenus.size());
            for (Menu menu : userMenus) {
				if (userMenuNames.contains(menu.getName())) {
					continue;
				} else {
					userMenuNames.add(menu.getName());
					distinctUserMenus.add(menu);
				}
			}
            log.sInfo("got total distinct granted menu : %s",distinctUserMenus.size());
            principal.setListMenu(distinctUserMenus);
            
        } catch (Throwable t) {
            t.printStackTrace();
        }

        return principal;
    }
	
	@Override
	public String add() {
		// TODO Auto-generated method stub
		return null;
	}

	@Override
	public String delete() {
		// TODO Auto-generated method stub
		return null;
	}

	@Override
	public String detail() {
		// TODO Auto-generated method stub
		return null;
	}

	@Override
	public String edit() {
		// TODO Auto-generated method stub
		return null;
	}

	@Override
	public String list() {
		// TODO Auto-generated method stub
		return null;
	}

	@Override
	public String save() {
		// TODO Auto-generated method stub
		return null;
	}
	
	@Override
	public String update() {
		// TODO Auto-generated method stub
		return null;
	}

	public void setMappedRequestFullPath(String actionMethod) {
        this.mappedRequest = actionMethod;
    }
	
	public void setMappedRequest(String actionMethod) {
        this.mappedRequest = getActionClass() + "_" + actionMethod;
    }

    public String getActionClass() {
        return getClass().getSimpleName();
    }

    public String getDestination() {
        return getClass().getSimpleName();
    }

    public String getActionMethod() {
        return mappedRequest;
    }

    public void setActionMethod(String method) {
        this.mappedRequest = method;
    }

    public String getSubaction() {
		return subaction;
	}

	public void setSubaction(String subaction) {
		this.subaction = subaction;
	}

	public String getLoginId() {
		return loginId;
	}

	public void setLoginId(String loginId) {
		this.loginId = loginId;
	}

	public String getPassword() {
		return password;
	}

	public void setPassword(String password) {
		this.password = password;
	}

	public User getUser() {
		return user;
	}

	public void setUser(User user) {
		this.user = user;
	}

	public String getCaptchaInput() {
		return captchaInput;
	}

	public void setCaptchaInput(String captchaInput) {
		this.captchaInput = captchaInput;
	}

	public String getJsonMessage() {
		return jsonMessage;
	}

	public void setJsonMessage(String jsonMessage) {
		this.jsonMessage = jsonMessage;
	}

	public String getMappedRequest() {
        return mappedRequest;
    }

    public String getPreviousPage() {
        return previousPage;
    }

    public void setPreviousPage(String previousPage) {
        this.previousPage = previousPage;
    }
    
}